<?php

class Soul_Db_Sql_Query extends Soul_Db_Sql_Where{

	private $_select = '';
	private $_from = '';
	private $_joins = array();
	private $_groupby = array();
	private $_orderby = array();
	private $_having = array();
	private $_limit = array();
    
	public function field($name, $as = NULL){
        $f = $this->addQualifier($name);
        if(!empty($as)){
            $f .= ' AS '.$this->addQualifier($as);
        }
        $this->_select .= empty($this->_select)? $f: ','.$f;
		return $this;
	}    

	public function select($select){
		$this->_select = $select;
		return $this;
	}

	public function from($table, $as = NULL){
		$this->_from = $this->addQualifier($table);
		if(!empty($as)){
			$this->_from .= ' AS '.$this->addQualifier($as);
		}
		return $this;
	}

	public function join($join){
		$this->_joins[] = $join;
		return $this;
	}
	
	public function joinInner($table, $alias, $onLeft, $onRight){
		return $this->join('INNER JOIN '.$this->addQualifier($table).' AS '.$this->addQualifier($alias)
							.' ON '.$this->addQualifier($onLeft).'='.$this->addQualifier($onRight));
	}

	public function joinLeft($table, $alias, $onLeft, $onRight){
		return $this->join('LEFT JOIN '.$this->addQualifier($table).' AS '.$this->addQualifier($alias)
							.' ON '.$this->addQualifier($onLeft).'='.$this->addQualifier($onRight));
	}

	public function joinRgith($table, $alias, $onLeft, $onRight){
		return $this->join('RIGHT JOIN '.$this->addQualifier($table).' AS '.$this->addQualifier($alias)
							.' ON '.$this->addQualifier($onLeft).'='.$this->addQualifier($onRight));
    }

	public function orderby($field, $dir = 'asc'){
		$dir = strtoupper($dir) == 'DESC'? 'DESC': 'ASC';
		$this->_orderby[] = $this->addQualifier($field).' '.$dir;
		return $this;
	}

	public function groupby(){
		$args = func_get_args();
		foreach($args as $item){
			$this->_groupby[] = $this->addQualifier($item);
		}
		return $this;
	}

	public function having($condition, $or = FALSE){
		if(count($this->_having) > 0){
			$this->_having[] = $or? 'OR': 'AND';
		}
		$this->_having[] = $condition;
		return $this;
	}

	public function limit($count, $offset = 0){
		$this->_limit = array($count, $offset);
		return $this;
	}

	public function pagination($index, $size){
		return $this->limit($size, ($index - 1) * $size);
	}

	public function reset(){
		$this->_select = '';
		$this->_from ='';
		$this->_joins = array();
		$this->_orderby = array();
		$this->_groupby = array();
		$this->_having = array();
		$this->_limit = array();
        $this->resetWhere();
		$this->resetParameter();
		return $this;
	}

	public function resetSelect(){
		$this->_select = '';
		return $this;
	}

	public function resetFrom(){
		$this->_from = '';
		return $this;
	}

	public function resetJoin(){
		$this->_joins = array();
		return $this;
	}

	public function resetOrderby(){
		$this->_orderby = array();
		return $this;
	}

	public function resetGroupby(){
		$this->_groupby = array();
		return $this;
	}

	public function resetHaving(){
		$this->_having = array();
		return $this;
	}

	public function resetLimit(){
		$this->_limit = array();
		return $this;
	}

	public function toSql(){
		$result = empty($this->_select)? "SELECT *": "SELECT ".$this->_select;
		$result .= " FROM ".$this->_from;
		if(count($this->_joins) > 0){
			$result .= ' '.implode(' ', $this->_joins);
		}
        $result .= parent::toSql();
		if(count($this->_groupby) > 0){
			$result .= ' GROUP BY '.implode(',', $this->_groupby);
		}
		if(count($this->_having) > 0){
			$result .= ' HAVING '.implode(',', $this->_having);
		}		
		if(count($this->_orderby) > 0){
			$result .= ' ORDER BY '.implode(',', $this->_orderby);
		}
		return $result;
	}

	public function toCountSql(){
		$result = "SELECT COUNT(*)";
		$result .= " FROM ".$this->_from;
		if(count($this->_joins) > 0){
			$result .= ' '.implode(' ', $this->_joins);
		}
		$result .= parent::toSql();
		return $result;
	}

	public function fetch($driver = NULL){
		$sql = $this->toSql();
        $driver = is_object($driver) ? $driver : Soul_Db_Factory::getDriver($driver);        
		if(count($this->_limit) >0){
			return $driver->setSql($sql, $this->getParameters())->fetchLimit($this->_limit[0], $this->_limit[1]);
		}

		return $driver->setSql($sql, $this->getParameters())->fetch();
	}

	public function fetchCount($driver = NULL){
		$sql = $this->toCountSql();
        $driver = is_object($driver) ? $driver : Soul_Db_Factory::getDriver($driver);   
		return $driver->setSql($sql, $this->getParameters())->fetch()->getFirstValue();
	}

	protected function addQualifier($field){
        if(strpos($field, ')') !== FALSE){
            return $field;
        }
        
		$arr = strpos($field, '.') === FALSE? array($field, ""): explode('.', $field);
		foreach($arr as &$item){
			if(!empty($item) && $item != '*' && $item[0] != '`' && $item[strlen($item) - 1] != '`'){
				$item = '`'.$item.'`';
			}
		}
		if(empty($arr[1])){
			return $arr[0];
		}
		return implode('.', $arr);
	}
}